package birdsong.comm;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.LinkedList;

import birdsong.comm.ServerSideMessage.Type;

/**
 * Communication manager for {@link birdsong.client.BirdsongClient Birdsong
 * clients}. Birdsong clients have this object to manage all the messages sent
 * by the server.
 * 
 * @author While True
 * @version 1
 */
public class DealWithServer {

        private Socket socket;
        private String clientNickname;
        private ClientCommunicator clientCommunicator;

        private ObjectInputStream in;
        private ObjectOutputStream out;

        private LinkedList<Thread> activeThreads = new LinkedList<Thread>();

        /**
         * Constructor that receives a socket and a ClientComunicator. Will generate
         * threads to take care of {@link OutputStream} and {@link InputStream}.
         * Will add all threads generated to listThreadsActive for interruption
         * purposes.
         * 
         * @param socket
         *            Socket for the network interface.
         * @param clientCommunicator
         *            ClientCommunicator responsible for the communication of the
         *            client.
         * @throws IOException
         *             Send an exception if the socket is closed.
         */
        public DealWithServer(Socket socket, String clientNickname,
                        ClientCommunicator clientCommunicator) throws IOException {
                this.socket = socket;
                this.clientNickname = clientNickname;
                this.clientCommunicator = clientCommunicator;
                in = new ObjectInputStream(socket.getInputStream());
                out = new ObjectOutputStream(socket.getOutputStream());

                getActiveThreads().add(new ThreadReceiverServer());
                getActiveThreads().add(new ThreadSenderServer());
                clientCommunicator.getClientSenderMessageList().add(new ServerMessage(Type.CLIENT_CONNECTED, null,      getClientNickname()));
 
        }

        /**
         * Starts the 2 Threads:
         * <ul>
         * ThreadReceiverServer - manage the incoming server messages.
         * </ul>
         * <ul>
         * ThreadSenderServer - manage the outcoming messages to the server.
         * </ul>
         */
        public void start() {
                for (Thread listThreads : getActiveThreads())
                        listThreads.start(); 
        }
 
        /**
         * Getter that returns the InputStreamer.
         * 
         * @return Returns the ObjectInputStream.
         */
        public ObjectInputStream getIn() {
                return in;
        }

        /**
         * Getter that returns the OutputStreamer.
         * 
         * @return Returns the ObjectInputStream.
         */
        public ObjectOutputStream getOut() {
                return out;
        }

        /**
         * Getter that returns the client nickname.
         * 
         * @return Returns the clientNickname.
         */
        public String getClientNickname() {
                return clientNickname;
        }

        public LinkedList<Thread> getActiveThreads() {
                return activeThreads;
        }

        private class ThreadReceiverServer extends Thread {
                @Override
                public void run() { 
                        try {
                                while (!isInterrupted()) {
                                        ClientMessage message = (ClientMessage) getIn().readObject();
                                        clientCommunicator.getClientReceiverMessageList().add(message); 
                                }
                        } catch (Exception e) {}
                }
        } 

        private class ThreadSenderServer extends Thread {
                @Override
                public void run() {
                        try {
                                while (!isInterrupted()) {
                                        ServerMessage message = clientCommunicator.getClientSenderMessageList().take();
                                        getOut().writeObject(message);  
                                        if (message.getType().equals(Type.CLIENT_DISCONNECTED)) {
                                                try {
                                                        socket.close();
                                                        this.interrupt();
                                                } catch (IOException e) {
                                                        e.printStackTrace(); 
                                                }
                                        }
                                }
                        } catch (Exception e) {
                                e.printStackTrace();
                        } 

                }

        }
}